package com.ivan.toolkit.swing;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;


public class Accordion extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = -2794996481194035727L;
	
	private List<AccordionPane> children = 
			new LinkedList<AccordionPane>();
	
	private AccordionPane selectedChild;
	
	private int titleHeight = 32;
	
	private Color normalColor1 = Color.DARK_GRAY;
	private Color normalColor2 = Color.lightGray;
	private Boolean normalReverse = false;
	private Color selectColor1 = Color.ORANGE.darker();
	private Color selectColor2 = Color.ORANGE.brighter();
	private Boolean selectReverse = false;
	

	/**
	 * Create the panel.
	 */
	public Accordion() {
		setLayout(null);
		this.addComponentListener(new ComponentListener() {

			@Override
			public void componentResized(ComponentEvent e) {
				updateLayout();
			}

			@Override
			public void componentMoved(ComponentEvent e) {
			}

			@Override
			public void componentShown(ComponentEvent e) {
			}

			@Override
			public void componentHidden(ComponentEvent e) {
			}
			
		});
	}
	
	public void addPane(Component comp, String title, Icon icon) {
		
		if(comp == null)
			return;
		
		if(title == null || title.isEmpty())
			return;
		
		for(AccordionPane iap : children) {
			if(iap.getContent().equals(comp)) {
				return;
			}
		}
		
		System.out.println("Add : " + title);
		
		AccordionPane pane = new AccordionPane();
		pane.setContent(comp);
		pane.getTitleLabel().setText(title);
		if(icon != null) {
			pane.getTitleLabel().setIcon(icon);
		}
		
		this.add(pane);
		
		children.add(pane);
		
		pane.getTitlePane().addMouseListener(new TitleMouseAdapter(pane));
		if(this.selectedChild == null) {
			this.selectedChild = pane;
		}
		
		// maybe it make the ui happy
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				updateLayout();
				updateColors();
			}
		});

	}
	
	public void removePane(Component comp) {
		for(AccordionPane iap : children) {
			
			if(iap.getContent().equals(comp)) {
				
				System.out.println("remove : " + iap.getTitleLabel().getText());
				
				if(this.selectedChild == iap) {
					this.selectedChild = null;
				}
				
				this.remove(iap);
				children.remove(iap);
				
				if(this.selectedChild == null) {
					if(!children.isEmpty())
						this.selectedChild = children.get(0);
				}
				
				// maybe it make the ui happy
				SwingUtilities.invokeLater(new Runnable() {
					@Override
					public void run() {
						updateLayout();
						updateColors();
					}
				});
				
				break;
			}
		}
	}
	
	public int getTitleHeight() {
		return titleHeight;
	}

	public void setTitleHeight(int titleHeight) {
		if(this.titleHeight != titleHeight) {
			this.titleHeight = titleHeight;
			updateLayout();
		}
	}
	
	

	public Color getNormalColor1() {
		return normalColor1;
	}

	public void setNormalColor1(Color normalColor1) {
		this.normalColor1 = normalColor1;
		updateColors();
	}

	public Color getNormalColor2() {
		return normalColor2;
	}

	public void setNormalColor2(Color normalColor2) {
		this.normalColor2 = normalColor2;
		updateColors();
	}

	public Boolean getNormalReverse() {
		return normalReverse;
	}

	public void setNormalReverse(Boolean normalReverse) {
		this.normalReverse = normalReverse;
		updateColors();
	}

	public Color getSelectColor1() {
		return selectColor1;
	}

	public void setSelectColor1(Color selectColor1) {
		this.selectColor1 = selectColor1;
		updateColors();
	}

	public Color getSelectColor2() {
		return selectColor2;
	}

	public void setSelectColor2(Color selectColor2) {
		this.selectColor2 = selectColor2;
		updateColors();
	}

	public Boolean getSelectReverse() {
		return selectReverse;
	}

	public void setSelectReverse(Boolean selectReverse) {
		this.selectReverse = selectReverse;
		updateColors();
	}

	private void updateLayout() {
		
		List<AccordionPane> copy = 
				new LinkedList<AccordionPane>();
		copy.addAll(children);
		
		int width = this.getWidth();
		int height = this.getHeight();
		
		int count = children.size();
		int viewPaneHeight = height - (this.titleHeight * count) + this.titleHeight;
		
		int y = 0;
		for(AccordionPane pane : copy) {
			if(pane == selectedChild) {
				pane.getTitlePane().setBackground(selectColor1);
				pane.getTitlePane().setBackground2(selectColor2);
				pane.getTitlePane().setReverseColors(selectReverse);
				pane.setBounds(0, y, width, viewPaneHeight);
				SwingUtilities.updateComponentTreeUI(pane);
				y += viewPaneHeight;
				pane.getContent().setVisible(true);
			} else {
				pane.getTitlePane().setBackground(normalColor1);
				pane.getTitlePane().setBackground2(normalColor2);
				pane.getTitlePane().setReverseColors(normalReverse);
				pane.setBounds(0, y, width, titleHeight);
				y += titleHeight;
				pane.getContent().setVisible(false);
			}
		}
	}
	
	private void updateColors() {
		
		List<AccordionPane> copy = 
				new LinkedList<AccordionPane>();
		copy.addAll(children);
		
		for(AccordionPane pane : copy) {
			if(pane == selectedChild) {
				pane.getTitlePane().setBackground(selectColor1);
				pane.getTitlePane().setBackground2(selectColor2);
				pane.getTitlePane().setReverseColors(selectReverse);
	
			} else {
				pane.getTitlePane().setBackground(normalColor1);
				pane.getTitlePane().setBackground2(normalColor2);
				pane.getTitlePane().setReverseColors(normalReverse);
			}
		}
	}
	
	protected void onAccordionPaneSelected() {
		
	}
	
	public Component getSelectedComponent() {
		if(this.selectedChild != null) {
			return this.selectedChild.getContent();
		}
		return null;
	}
	
	class TitleMouseAdapter extends MouseAdapter {
		
		private AccordionPane pane;

		public TitleMouseAdapter(AccordionPane pane) {
			super();
			this.pane = pane;
		}

		@Override
		public void mousePressed(MouseEvent e) {
			if(selectedChild != pane) {
				selectedChild = pane;
				updateLayout();
				onAccordionPaneSelected();
			}
		}
		
		

	}

}
